package chips

import (
	"chips/baseChips"
	"fmt"
)

var (
	Xor = baseChips.Xor
	And = baseChips.And
	Or  = baseChips.Or
	Nor = baseChips.Nor
	Not = baseChips.Not
	Bit = DFF
)

//加法器
func HalfAdder(a bool, b bool) (sum bool, carry bool) {
	return Xor(a, b), And(a, b)
}

func FullAdder(a bool, b bool, c bool) (sum bool, carry bool) {
	s1, c1 := HalfAdder(a, b)
	s2, c2 := HalfAdder(s1, c)
	return s2, Or(c1, c2)
}

func FourBitAdder(a3 bool, b3 bool, a2 bool, b2 bool, a1 bool, b1 bool, a bool, b bool) (sum []bool, c bool) {
	tS, tC := FullAdder(a, b, false)
	tS1, tC1 := FullAdder(a1, b1, tC)
	tS2, tC2 := FullAdder(a2, b2, tC1)
	tS3, tC3 := FullAdder(a3, b3, tC2)
	return []bool{
		tS3, tS2, tS1, tS,
	}, tC3
}

//8位加法器
func Bit8Adder(a [8]bool, b [8]bool) [8]bool {
	ts := [8]bool{}
	tc := [8]bool{}

	for i := 0; i < len(ts); i++ {
		if i == 0 {
			tts, ttc := HalfAdder(a[i], b[i])
			ts[i] = tts
			tc[i] = ttc
		} else {
			tts, ttc := FullAdder(a[i], b[i], tc[i-1])
			ts[i] = tts
			tc[i] = ttc
		}
	}
	return ts
}

//16位加法器
func Bit16Adder(a [16]bool, b [16]bool) [16]bool {
	ts := [16]bool{}
	tc := [16]bool{}

	for i := 0; i < len(ts); i++ {
		if i == 0 {
			tts, ttc := HalfAdder(a[i], b[i])
			ts[i] = tts
			tc[i] = ttc
		} else {
			tts, ttc := FullAdder(a[i], b[i], tc[i-1])
			ts[i] = tts
			tc[i] = ttc
		}
	}
	return ts
}

func Inc16(in [16]bool) [16]bool {
	return Bit16Adder(in, [16]bool{true})
}

//PC
func PC() func(in [16]bool, load bool, inc bool, reset bool) [16]bool {
	preOut := [16]bool{}
	addOut := [16]bool{}
	register := Register()
	return func(in [16]bool, load bool, inc bool, reset bool) [16]bool {
		o1 := baseChips.Mux16(preOut, addOut, inc)
		o2 := baseChips.Mux16(o1, in, load)
		o3 := baseChips.Mux16(o2, [16]bool{}, reset)
		preOut = register(o3, true)
		addOut = Inc16(preOut)
		return addOut
	}
}

//存储器
func FF() func(inA bool, inB bool) bool {
	ffTemp := false
	return func(inA bool, inB bool) bool {
		ffTemp = Nor(Nor(inA, ffTemp), inB)
		return ffTemp
	}
}

func DFF() func(data bool, keep bool) bool {
	ff := FF()
	return func(data bool, keep bool) bool {
		return ff(And(data, keep), And(Not(data), keep))
	}
}

//8位锁存器
func EightDFF() func(inData [8]bool, clock bool) [8]bool {
	var dffs [8]func(data bool, keep bool) bool
	for i := 0; i < 8; i++ {
		dffs[i] = DFF()
	}
	return func(inData [8]bool, clock bool) [8]bool {
		var rs [8]bool
		for i, ff := range dffs {
			rs[i] = ff(inData[i], clock)
		}
		return rs
	}
}

func DFF16() func(inData [16]bool, clock bool) [16]bool {
	var dffs [16]func(data bool, keep bool) bool
	for i := 0; i < len(dffs); i++ {
		dffs[i] = DFF()
	}
	return func(inData [16]bool, clock bool) [16]bool {
		var rs [16]bool
		for i, ff := range dffs {
			rs[i] = ff(inData[i], clock)
		}
		return rs
	}
}

//8 位
func CEightDFF() func(data bool, clock [8]bool) [8]bool {
	var dffs [8]func(data bool, keep bool) bool
	for i := 0; i < 8; i++ {
		dffs[i] = DFF()
	}

	return func(data bool, clock [8]bool) [8]bool {
		var rs [8]bool
		for i, ff := range dffs {
			rs[i] = ff(data, clock[i])
		}
		return rs
	}
}

//register
func Register() func(in [16]bool, load bool) [16]bool {
	var dffs [16]func(data bool, keep bool) bool
	for i := 0; i < 16; i++ {
		dffs[i] = DFF()
	}
	return func(in [16]bool, load bool) [16]bool {
		var rs [16]bool
		for i, ff := range dffs {
			rs[i] = ff(in[i], load)
		}
		return rs
	}
}

func Mem() func(point [3]bool, w bool, d bool) {
	cEightDFF := CEightDFF()
	return func(point [3]bool, w bool, d bool) {
		fmt.Println(point, ThreeWayToO(point, cEightDFF(d, ThreeWayToEight(point[0], point[1], point[2], w))))
	}
}

//RAM8
func RAM8() func(in [16]bool, load bool, address [3]bool) (out [16]bool) {
	var registers [16]func(in [16]bool, load bool) [16]bool
	for i := 0; i < (len(registers) / 2); i++ {
		registers[i] = Register()
	}

	return func(in [16]bool, load bool, address [3]bool) (out [16]bool) {
		var rs = [8][16]bool{}
		loadA, loadB, loadC, loadD, loadE, loadF, loadG, loadH := baseChips.DMux8Way(load, address)
		rs[0] = registers[0](in, loadA)
		rs[1] = registers[1](in, loadB)
		rs[2] = registers[2](in, loadC)
		rs[3] = registers[3](in, loadD)
		rs[4] = registers[4](in, loadE)
		rs[5] = registers[5](in, loadF)
		rs[6] = registers[6](in, loadG)
		rs[7] = registers[7](in, loadH)
		return baseChips.Mux8Way16(rs[0], rs[1], rs[2], rs[3], rs[4], rs[5], rs[6], rs[7], address)
	}
}

//RAN 64
func RAM64() func(in [16]bool, load bool, address [6]bool) (out [16]bool) {
	var ram8s [8]func(in [16]bool, load bool, address [3]bool) (out [16]bool)
	for i := 0; i < len(ram8s); i++ {
		ram8s[i] = RAM8()
	}
	return func(in [16]bool, load bool, address [6]bool) (out [16]bool) {
		var rs = [8][16]bool{}
		loadA, loadB, loadC, loadD, loadE, loadF, loadG, loadH := baseChips.DMux8Way(load, [3]bool{address[3], address[4], address[5]})
		rs[0] = ram8s[0](in, loadA, [3]bool{address[0], address[1], address[2]})
		rs[1] = ram8s[1](in, loadB, [3]bool{address[0], address[1], address[2]})
		rs[2] = ram8s[2](in, loadC, [3]bool{address[0], address[1], address[2]})
		rs[3] = ram8s[3](in, loadD, [3]bool{address[0], address[1], address[2]})
		rs[4] = ram8s[4](in, loadE, [3]bool{address[0], address[1], address[2]})
		rs[5] = ram8s[5](in, loadF, [3]bool{address[0], address[1], address[2]})
		rs[6] = ram8s[6](in, loadG, [3]bool{address[0], address[1], address[2]})
		rs[7] = ram8s[7](in, loadH, [3]bool{address[0], address[1], address[2]})

		return baseChips.Mux8Way16(rs[0], rs[1], rs[2], rs[3], rs[4], rs[5], rs[6], rs[7], [3]bool{address[3], address[4], address[5]})
	}
}

//RAM512
func RAM512() func(in [16]bool, load bool, address [9]bool) (out [16]bool) {
	var rams [8]func(in [16]bool, load bool, address [6]bool) (out [16]bool)
	for i := 0; i < len(rams); i++ {
		rams[i] = RAM64()
	}
	return func(in [16]bool, load bool, address [9]bool) (out [16]bool) {
		var rs = [8][16]bool{}
		var ramsAddress = [6]bool{address[0], address[1], address[2], address[3], address[4], address[5]}
		var controlAddress = [3]bool{address[6], address[7], address[8]}

		loadA, loadB, loadC, loadD, loadE, loadF, loadG, loadH := baseChips.DMux8Way(load, controlAddress)

		rs[0] = rams[0](in, loadA, ramsAddress)
		rs[1] = rams[1](in, loadB, ramsAddress)
		rs[2] = rams[2](in, loadC, ramsAddress)
		rs[3] = rams[3](in, loadD, ramsAddress)
		rs[4] = rams[4](in, loadE, ramsAddress)
		rs[5] = rams[5](in, loadF, ramsAddress)
		rs[6] = rams[6](in, loadG, ramsAddress)
		rs[7] = rams[7](in, loadH, ramsAddress)

		return baseChips.Mux8Way16(rs[0], rs[1], rs[2], rs[3], rs[4], rs[5], rs[6], rs[7], controlAddress)
	}
}

//RAM4K
func RAM4K() func(in [16]bool, load bool, address [12]bool) (out [16]bool) {
	var rams [8]func(in [16]bool, load bool, address [9]bool) (out [16]bool)
	for i := 0; i < len(rams); i++ {
		rams[i] = RAM512()
	}
	return func(in [16]bool, load bool, address [12]bool) (out [16]bool) {
		var rs = [8][16]bool{}
		var ramsAddress = [9]bool{address[0], address[1], address[2], address[3], address[4], address[5], address[6], address[7], address[8]}
		var controlAddress = [3]bool{address[9], address[10], address[11]}

		loadA, loadB, loadC, loadD, loadE, loadF, loadG, loadH := baseChips.DMux8Way(load, controlAddress)

		rs[0] = rams[0](in, loadA, ramsAddress)
		rs[1] = rams[1](in, loadB, ramsAddress)
		rs[2] = rams[2](in, loadC, ramsAddress)
		rs[3] = rams[3](in, loadD, ramsAddress)
		rs[4] = rams[4](in, loadE, ramsAddress)
		rs[5] = rams[5](in, loadF, ramsAddress)
		rs[6] = rams[6](in, loadG, ramsAddress)
		rs[7] = rams[7](in, loadH, ramsAddress)

		return baseChips.Mux8Way16(rs[0], rs[1], rs[2], rs[3], rs[4], rs[5], rs[6], rs[7], controlAddress)
	}
}

//RAM16K
func RAM16K() func(in [16]bool, load bool, address [14]bool) (out [16]bool) {
	var rams [8]func(in [16]bool, load bool, address [12]bool) (out [16]bool)
	for i := 0; i < len(rams); i++ {
		rams[i] = RAM4K()
	}
	return func(in [16]bool, load bool, address [14]bool) (out [16]bool) {
		var rs = [8][16]bool{}
		var ramsAddress = [12]bool{address[0], address[1], address[2], address[3], address[4], address[5], address[6], address[7], address[8], address[9], address[10], address[11]}
		var controlAddress = [2]bool{address[12], address[13]}

		loadA, loadB, loadC, loadD := baseChips.DMux4Way(load, controlAddress)

		rs[0] = rams[0](in, loadA, ramsAddress)
		rs[1] = rams[1](in, loadB, ramsAddress)
		rs[2] = rams[2](in, loadC, ramsAddress)
		rs[3] = rams[3](in, loadD, ramsAddress)

		return baseChips.Mux4Way16(rs[0], rs[1], rs[2], rs[3], controlAddress)
	}
}

//RAM64K
func RAM64K() func(in [16]bool, load bool, address [16]bool) (out [16]bool) {
	var rams [8]func(in [16]bool, load bool, address [14]bool) (out [16]bool)
	for i := 0; i < len(rams); i++ {
		rams[i] = RAM16K()
	}
	return func(in [16]bool, load bool, address [16]bool) (out [16]bool) {
		var rs = [8][16]bool{}
		var ramsAddress = [14]bool{address[0], address[1], address[2], address[3], address[4], address[5], address[6], address[7], address[8], address[9], address[10], address[11], address[12], address[13]}
		var controlAddress = [2]bool{address[14], address[15]}

		loadA, loadB, loadC, loadD := baseChips.DMux4Way(load, controlAddress)

		rs[0] = rams[0](in, loadA, ramsAddress)
		rs[1] = rams[1](in, loadB, ramsAddress)
		rs[2] = rams[2](in, loadC, ramsAddress)
		rs[3] = rams[3](in, loadD, ramsAddress)

		return baseChips.Mux4Way16(rs[0], rs[1], rs[2], rs[3], controlAddress)
	}
}

func OneToTwo(in bool, sel bool) (bool, bool) {
	return And(Not(sel), in), And(in, sel)
}

func ThreeWayToOne(point [2]bool, a bool, b bool, c bool) bool {
	row1 := Or(And(And(And(Not(point[0]), Not(point[1])), Not(a)), c), And(And(And(Not(point[0]), Not(point[1])), a), c))
	row2 := Or(And(And(And(Not(point[0]), point[1]), b), c), And(And(And(Not(point[0]), point[1]), b), Not(c)))
	row3 := Or(And(And(And(point[0], Not(point[1])), a), b), And(And(And(point[0], Not(point[1])), a), Not(b)))
	return Or(Or(row1, row2), row3)
}

func ThreeWayToEight(a bool, b bool, c bool, set bool) [8]bool {
	createFn := func(a bool, b bool, c bool, set bool) bool {
		return And(And(And(a, b), c), set)
	}

	return [8]bool{
		createFn(Not(a), Not(b), Not(c), set),
		createFn(Not(a), Not(b), c, set),
		createFn(Not(a), b, Not(c), set),
		createFn(Not(a), b, c, set),
		createFn(a, Not(b), Not(c), set),
		createFn(a, Not(b), c, set),
		createFn(a, b, Not(c), set),
		createFn(a, b, c, set),
	}
}

func ThreeWayToO(point [3]bool, in [8]bool) bool {
	createFn := func(p1 bool, p2 bool, p3 bool, d bool) bool {
		return And(And(And(p1, p2), p3), d)
	}

	createOrFn := func(o1 bool, o2 bool, o3 bool, o4 bool, o5 bool, o6 bool, o7 bool, o8 bool) bool {
		return Or(Or(Or(Or(Or(Or(Or(o1, o2), o3), o4), o5), o6), o7), o8)
	}

	return createOrFn(
		createFn(Not(point[0]), Not(point[1]), Not(point[2]), in[0]),
		createFn(Not(point[0]), Not(point[1]), point[2], in[1]),
		createFn(Not(point[0]), point[1], Not(point[2]), in[2]),
		createFn(Not(point[0]), point[1], point[2], in[3]),
		createFn(point[0], Not(point[1]), Not(point[2]), in[4]),
		createFn(point[0], Not(point[1]), point[2], in[5]),
		createFn(point[0], point[1], Not(point[2]), in[6]),
		createFn(point[0], point[1], point[2], in[7]),
	)
}

func TransIntToBool(num int) bool {
	if num == 1 {
		return true
	} else {
		return false
	}
}

func TransBoolToInt(b bool) int {
	if b {
		return 1
	} else {
		return 0
	}
}

func SimplePc() func() {
	ram64k := RAM64K()
	dFF16 := DFF16()
	sT := [16]bool{}
	pc := PC()

	//先设置几个数据
	ram64k([16]bool{true}, true, [16]bool{true, false, false, false, false, false, false, false, false, false, false, false, false, false})
	ram64k([16]bool{true, true, true}, true, [16]bool{false, true, false, false, false, false, false, false, false, false, false, false, false, false})
	ram64k([16]bool{true, true}, true, [16]bool{true, true, false, false, false, false, false, false, false, false, false, false, false, false})

	return func() {
		pcOut := pc([16]bool{}, false, true, false)
		//fmt.Println(pcOut)
		ramOut := ram64k([16]bool{}, false, pcOut)
		fmt.Println(ramOut, pcOut)
		sT = dFF16(Bit16Adder(ramOut, sT), true)
		fmt.Println(sT)
	}
}
